#include "stm32f10x.h"                  // Device header
#include "apds9960.h"
#include "Delay.h"
#include "apds9960_IIC.h"

bool SparkFun_APDS9960_init(void);
bool enableGestureSensor(bool interrupts);

extern int abs(int __x); 

void Wire_begin_(void);

/* Container for gesture data */
typedef struct gesture_data_type {
    uint8_t u_data[32];
    uint8_t d_data[32];
    uint8_t l_data[32];
    uint8_t r_data[32];
    uint8_t index;
    uint8_t total_gestures;
    uint8_t in_threshold;
    uint8_t out_threshold;
} gesture_data_type;


/* Members */
gesture_data_type gesture_data_;


int gesture_ud_delta_;
int gesture_lr_delta_;
int gesture_ud_count_;
int gesture_lr_count_;
int gesture_near_count_;
int gesture_far_count_;
int gesture_state_;
int gesture_motion_;

/**
 * @brief Constructor - Instantiates SparkFun_APDS9960 object
 */
bool SparkFun_APDS9960_Init_ALL(void)
{
    gesture_ud_delta_ = 0;//UP -->DOWN
    gesture_lr_delta_ = 0;//LEFT--> RIGHT
    
    gesture_ud_count_ = 0;
    gesture_lr_count_ = 0;
    
    gesture_near_count_ = 0;
    gesture_far_count_ = 0;
    
    gesture_state_ = 0;
    gesture_motion_ = DIR_NONE;

	return (SparkFun_APDS9960_init())&&(enableGestureSensor(true));	//返回正成功，false失败
}

/**
 * @brief Configures I2C communications and initializes registers to defaults
 *
 * @return True if initialized successfully. False otherwise.
 */
bool SparkFun_APDS9960_init(void)
{
//    uint8_t id,*pid;

    /* Initialize I2C */
    Wire_begin_();//初始化I2C
     
    /* 读取器件ID 0x92 = 0xAB */
//    if( !wireReadDataByte(APDS9960_ID, pid) ) 
//	{
//		return false;
//	}	
//	id=*pid;
//	printf("id = %.2x\n",id);// 打印器件ID = 0xAB
//    if( !((id == APDS9960_ID_1 || id == APDS9960_ID_2)) ) 
//	{
//        return false;
//    }
//		
	
    /* 失能失能寄存器0x80 = 0x00 */
    if( !setMode(ALL, OFF) ) //(7,0)
	{
        return false;
    }
    
	//设置手势接近进入(手势状态机)阀值为0xA0 = 40
    /* 设置手势传感器寄存器默认值 */
    if( !setGestureEnterThresh(DEFAULT_GPENTH) ) 
	{
        return false;
    } 

	//设置手势接近退出(手势状态机)阀值为0xA1 = 30
    if( !setGestureExitThresh(DEFAULT_GEXTH) ) 
	{
        return false;
    }
	
	//设置配置寄存器1 0xA2 = 0x40
	//1.在4个数据集被添加到FIFO里后产生中断
	//2.All UDLR 探测数据被包含到集合中
	//3.手势退出持久性.当连续的手势结束发生称为比GEXPERS大于或等于的值时，
	//  手势状态机退出(第1个手势结束发生导致手势状态机退出)
    if( !wireWriteDataByte(APDS9960_GCONF1, DEFAULT_GCONF1) ) 
	{ 
        return false;
    }
	
	//设置配置寄存器2 0xA3 的 bit 6:5 = 10  4x增益
    if( !setGestureGain(DEFAULT_GGAIN) ) 
	{
        return false;
    }   
	
	//设置配置寄存器2 0xA3 的 bit 4:3 = 00  100ma
    if( !setGestureLEDDrive(DEFAULT_GLDRIVE) ) 
	{
        return false;
    }     
	
	//设定配置寄存器2 0xA3 的 bit 2:0=001   2.8ms
    if( !setGestureWaitTime(DEFAULT_GWTIME) ) 
	{
        return false;
    } 
	
	//设置手势UP偏移寄存器 0xA4 = 0 没有偏移
    if( !wireWriteDataByte(APDS9960_GOFFSET_U, DEFAULT_GOFFSET) ) 
	{
        return false;
    }   

	//设置手势DOWN偏移寄存器 0xA5 = 0 没有偏移
    if( !wireWriteDataByte(APDS9960_GOFFSET_D, DEFAULT_GOFFSET) ) 
	{
        return false;
    }
	
	//设置手势LEFT偏移寄存器 0xA7 = 0 没有偏移
    if( !wireWriteDataByte(APDS9960_GOFFSET_L, DEFAULT_GOFFSET) ) 
	{
        return false;
    }         
	
	//设置手势RIGHT偏移寄存器 0xA9 = 0 没有偏移
    if( !wireWriteDataByte(APDS9960_GOFFSET_R, DEFAULT_GOFFSET) ) 
	{
        return false;
    }
	
	//设置收势脉冲数和脉宽寄存器0xA6 = 0xC9   32us, 10 pulses
    if( !wireWriteDataByte(APDS9960_GPULSE, DEFAULT_GPULSE) ) 
	{
        return false;
    }
	
	//设置配置寄存器3  0xAA 的bit 1:0 = 00  所有光电二极管在手势期间均有效
    if( !wireWriteDataByte(APDS9960_GCONF3, DEFAULT_GCONF3) ) 
	{
        return false;
    }
	
	//设置配置寄存器4 0xAB 的bit1 = 0 关闭手势中断 GIEN=0
    if( !setGestureIntEnable(DEFAULT_GIEN) ) 
	{
        return false;
    }
		
	return true;
		
}
/*******************************************************************************
 * Public methods for controlling the APDS-9960
 ******************************************************************************/

/**
 * @brief Reads and returns the contents of the ENABLE register
 *
 * @return Contents of the ENABLE register. 0xFF if error.
 */
uint8_t getMode(void)
{
    uint8_t enable_value;
    
    /* Read current ENABLE register */
    if( !wireReadDataByte(APDS9960_ENABLE, &enable_value) )		
	{
        return ERROR;
    }
    
    return enable_value;
}

/**
 * @brief Enables or disables a feature in the APDS-9960
 *
	#define POWER                   0
	#define AMBIENT_LIGHT           1
	#define PROXIMITY               2
	#define WAIT                    3
	#define AMBIENT_LIGHT_INT       4
	#define PROXIMITY_INT           5
	#define GESTURE                 6
	#define ALL                     7
 * @param[in] mode which feature to enable
 * @param[in] enable ON (1) or OFF (0)
 * @return True if operation success. False otherwise.
	mode = ALL 7 enable = OFF  0
 */
bool setMode(int8_t mode, uint8_t enable)
{
    uint8_t reg_val;

    /* Read current ENABLE register */
    reg_val = getMode();
	//printf("First_setMode_regval = %.2x\n",reg_val);//打印读取到的使能寄存器的值 0x80 = 0x4d
    if( reg_val == ERROR ) {//如果读取到的值为0xFF，则错误
        return false;
    }
    
    /* Change bit(s) in ENABLE register */
    enable = enable & 0x01;
    if((mode >= 0) && (mode <= 6)) //使能或失能某个位
	{
		if(enable) //使能
		{
            reg_val |= (1 << mode);
        } 
		else //失能
		{
            reg_val &= ~(1 << mode);
        }
    } 
	else if( mode == ALL ) //使能全部
	{
        if (enable) 
		{
            reg_val = 0x7F;//0x80=0x7F   全部使能
        } 
		else //全部使能
		{
            reg_val = 0x00;//0x80=0x00
		//	printf("0x80 = 0x00 all disable\n");
        }
    }
      
	//printf("Last_setMode_regval = %.2x\n",reg_val);//打印读取到的使能寄存器的值 0x80 = 0x4d
    /* Write value back to ENABLE register */
    if( !wireWriteDataByte(APDS9960_ENABLE, reg_val) )		
	{
        return false;
    }
        
    return true;
}

/**
 * @brief Starts the gesture recognition engine on the APDS-9960
 *
 * @param[in] interrupts true to enable hardware external interrupt on gesture
 * @return True if engine enabled correctly. False on error.
 */
bool enableGestureSensor(bool interrupts)
{
    
    /* Enable gesture mode
       Set ENABLE to 0 (power off)
       Set WTIME to 0xFF
       Set AUX to LED_BOOST_300
       Enable PON, WEN, PEN, GEN in ENABLE 
    */
	  //interrupts = true;
	
    resetGestureParameters();//复位手势变量=0
	
	//设置等待时间寄存器0x83 = 0xFF (WLONG=1  0.03s)   (WLONG=0   2.78ms)
    if( !wireWriteDataByte(APDS9960_WTIME, 0xFF) ) //
	{
        return false;
    }
	
	//设置接近脉冲计数寄存器 0x8E = 0x89 16us, 10 pulses
    if( !wireWriteDataByte(APDS9960_PPULSE, DEFAULT_GESTURE_PPULSE) ) 
	{
        return false;
    }
	
	//设置配置寄存器2 0x90的bit5:4=11  %300   LED驱动电流
    if( !setLEDBoost(LED_BOOST_300) ) 
	{
        return false;
    }
	
	//是否开启手势中断配置寄存器4  0xAB 
    if( interrupts ) 
	{
        if( !setGestureIntEnable(1) ) 
		{
            return false;
        }
    } 
	else 
	{
        if( !setGestureIntEnable(0) ) 
		{
            return false;
        }
    }
	
	//设置手势模式GMODE = 1
    if( !setGestureMode(1) ) 
	{
        return false;
    }
	
	//PON = 1  0x80 的 bit0 = 1
    if( !enablePower() )
	{
        return false;
    }
	
	//WEN = 1   0x80 的 bit3 = 1
    if( !setMode(WAIT, 1) ) 
	{
        return false;
    }
	
	//PEN=1   0x80 的 bit2 = 1
    if( !setMode(PROXIMITY, 1) ) 
	{
        return false;
    }
	
	//PIEN=1   0x80 的 bit6 = 1
    if( !setMode(GESTURE, 1) ) 
	{
        return false;
    }
    
    return true;
}


/**
 * @brief Determines if there is a gesture available for reading
 *
 * @return True if gesture available. False otherwise.
 */
bool isGestureAvailable(void)
{
    uint8_t val;
    
    /*读0xAF*/
    if( !wireReadDataByte(APDS9960_GSTATUS, &val) ) 
	{
        return ERROR;
    }
   // printf("0xAF_val = %.2x\n",val);
    /* Shift and mask out GVALID bit */
    val&=APDS9960_GVALID;//判断0xAF最低位GVALID是否为1
    
    /* Return true/false based on GVALID bit */
    if( val == 1) 
	{
        return true;
    } 
	else 
	{
        return false;
    }
}

/**
 * @brief Processes a gesture event and returns best guessed gesture
 *
 * @return Number corresponding to gesture. -1 on error.
 */
int readGesture(void)
{
    uint8_t fifo_level = 0;
    int8_t bytes_read = 0;
    uint8_t fifo_data[128];
    uint8_t gstatus;
    int motion;
    int i;
    
    /* Make sure that power and gesture is on and data is valid */
    if(!isGestureAvailable()||!(getMode()&01000001) ) 
	{
        return DIR_NONE;
    }
    
    /* Keep looping as long as gesture data is valid */
    while(1) 
	{
    
        /* Wait some time to collect next batch of FIFO data */
        Delay_ms(FIFO_PAUSE_TIME);
        
        /* Get the contents of the STATUS register. Is data still valid? */
        if( !wireReadDataByte(APDS9960_GSTATUS, &gstatus) ) 
		{
            return ERROR;
        }
        //printf("gstatus = %.2x\n",gstatus);
        /* If we have valid data, read in FIFO */
        if((gstatus & APDS9960_GVALID)==APDS9960_GVALID) 
		{
        
            /* Read the current FIFO level */
            if( !wireReadDataByte(APDS9960_GFLVL, &fifo_level) ) 
			{
                return ERROR;
            }
			//printf("fifo_level = 0x%.2x\n",fifo_level);//fifo中数据的多少

            /* If there's stuff in the FIFO, read it into our data block */
            if( fifo_level > 0) 
			{
				bytes_read = wireReadDataBlock(  APDS9960_GFIFO_U, 
                                                (uint8_t*)fifo_data, 
                                                (fifo_level * 4) );
			
#if	DEBUG
//				for(i = 0;i<fifo_level*4;i = i+4)
//				{
//					printf("=========================\n");
//					printf("%d fifo_level data\n",i/4);
//					printf("U = 0x%.2x  ",fifo_data[i+0]);
//					printf("D = 0x%.2x  ",fifo_data[i+1]);
//					printf("L = 0x%.2x  ",fifo_data[i+2]);
//					printf("R = 0x%.2x  \n",fifo_data[i+3]);
//					printf("=========================\n");
//					printf("\n");
//				}
//				printf("bytes_read = %d\n",bytes_read);
#endif
                if(bytes_read==-1) 
				{
                    return ERROR;
                }

                /* If at least 1 set of data, sort the data into U/D/L/R */
                if( bytes_read >= 4 ) 
				{
                    for( i = 0; i < bytes_read; i += 4 ) 
					{
                        gesture_data_.u_data[gesture_data_.index] = \
                                                            fifo_data[i + 0];
                        gesture_data_.d_data[gesture_data_.index] = \
                                                            fifo_data[i + 1];
                        gesture_data_.l_data[gesture_data_.index] = \
                                                            fifo_data[i + 2];
                        gesture_data_.r_data[gesture_data_.index] = \
                                                            fifo_data[i + 3];
                        gesture_data_.index++;
                        gesture_data_.total_gestures++;
                    }
//                    printf("gesture_data_.index = %d\n",gesture_data_.index);
//					printf("gesture_data_.total_gestures = %d\n",gesture_data_.total_gestures);

                    /* Filter and process gesture data. Decode near/far state */
                    if( processGestureData() ) 
					{
                        if( decodeGesture() ) 
						{
                            //***TODO: U-Turn Gestures
                        }
                    }
                    
                    /* Reset data */
                    gesture_data_.index = 0;
                    gesture_data_.total_gestures = 0;
                }
            }
        } 
		else 
		{
            /* Determine best guessed gesture and clean up */
            Delay_ms(FIFO_PAUSE_TIME);
            decodeGesture();
            motion = gesture_motion_;
            resetGestureParameters();
            return motion;
        }
    }
}


/**
 * Turn the APDS-9960 on
 *
 * @return True if operation successful. False otherwise.
 */
bool enablePower(void)
{
	if( !setMode(POWER, 1) ) 
	{
		return false;
	}

	return true;
}

/**
 * Turn the APDS-9960 off
 *
 * @return True if operation successful. False otherwise.
 */
bool disablePower(void)
{
    if( !setMode(POWER, 0) ) 
	{
        return false;
    }
    
    return true;
}


/*******************************************************************************
 * High-level gesture controls
 ******************************************************************************/

/**
 * @brief Resets all the parameters in the gesture data member
 */
void resetGestureParameters(void)
{
    gesture_data_.index = 0;
    gesture_data_.total_gestures = 0;
    
    gesture_ud_delta_ = 0;
    gesture_lr_delta_ = 0;
    
    gesture_ud_count_ = 0;
    gesture_lr_count_ = 0;
    
    gesture_near_count_ = 0;
    gesture_far_count_ = 0;
    
    gesture_state_ = 0;
    gesture_motion_ = DIR_NONE;
}

/**
 * 处理原始手势数据确定滑动方向
 *
 * @return True if near or far state seen. False otherwise.
 */
bool processGestureData(void)
{
    uint8_t u_first = 0;
    uint8_t d_first = 0;
    uint8_t l_first = 0;
    uint8_t r_first = 0;
    uint8_t u_last = 0;
    uint8_t d_last = 0;
    uint8_t l_last = 0;
    uint8_t r_last = 0;
    int ud_ratio_first;
    int lr_ratio_first;
    int ud_ratio_last;
    int lr_ratio_last;
    int ud_delta;
    int lr_delta;
    int i;

    /* If we have less than 4 total gestures, that's not enough */
    if( gesture_data_.total_gestures <= 4 ) 
	{
        return false;
    }
    
    /* Check to make sure our data isn't out of bounds */
    if( (gesture_data_.total_gestures <= 32) && \
        (gesture_data_.total_gestures > 0) ) 
	{
        
        /* Find the first value in U/D/L/R above the threshold */
        for( i = 0; i < gesture_data_.total_gestures; i++ ) 
		{		
			if( (gesture_data_.u_data[i] > GESTURE_THRESHOLD_OUT) &&
                (gesture_data_.d_data[i] > GESTURE_THRESHOLD_OUT) &&
                (gesture_data_.l_data[i] > GESTURE_THRESHOLD_OUT) &&
                (gesture_data_.r_data[i] > GESTURE_THRESHOLD_OUT) ) 
			{
                
                u_first = gesture_data_.u_data[i];
                d_first = gesture_data_.d_data[i];
                l_first = gesture_data_.l_data[i];
                r_first = gesture_data_.r_data[i];
#if DEBUG
//				printf("*********************************************\n");
//				printf("Finding first:\n");
//				printf("u_first = %d\n",u_first);
//				printf("d_first = %d\n",d_first);
//				printf("l_first = %d\n",l_first);
//				printf("r_first = %d\n",r_first);
//				printf("First i = %d\n",i);
//				printf("*********************************************\n");
#endif
                break;
            }
        }
        /* If one of the _first values is 0, then there is no good data */
        if( (u_first == 0) || (d_first == 0) || \
            (l_first == 0) || (r_first == 0) ) 
		{
            
            return false;
        }
        /* Find the last value in U/D/L/R above the threshold */
        for( i = gesture_data_.total_gestures - 1; i >= 0; i-- ) 
		{
            if( (gesture_data_.u_data[i] > GESTURE_THRESHOLD_OUT) &&
                (gesture_data_.d_data[i] > GESTURE_THRESHOLD_OUT) &&
                (gesture_data_.l_data[i] > GESTURE_THRESHOLD_OUT) &&
                (gesture_data_.r_data[i] > GESTURE_THRESHOLD_OUT) ) 
			{
                
                u_last = gesture_data_.u_data[i];
                d_last = gesture_data_.d_data[i];
                l_last = gesture_data_.l_data[i];
                r_last = gesture_data_.r_data[i];
#if DEBUG
//				printf("*********************************************\n");
//				printf("Finding last:\n");
//				printf("u_last = %d\n",u_last);
//				printf("d_last = %d\n",d_last);
//				printf("l_last = %d\n",l_last);
//				printf("r_last = %d\n",r_last);
//				printf("Last i = %d\n",i);
//				printf("*********************************************\n");
#endif
                break;
            }
        }
    }
    
    /* Calculate the first vs. last ratio of up/down and left/right */
    ud_ratio_first = ((u_first - d_first) * 100) / (u_first + d_first);
    lr_ratio_first = ((l_first - r_first) * 100) / (l_first + r_first);
    ud_ratio_last = ((u_last - d_last) * 100) / (u_last + d_last);
    lr_ratio_last = ((l_last - r_last) * 100) / (l_last + r_last);
       
#if DEBUG
//	printf("===============================================\n");
//	printf("first vs last ratio :\n");
//	printf("ud_ratio_first = %d\n",ud_ratio_first);
//	printf("lr_ratio_first = %d\n",lr_ratio_first);
//	printf("ud_ratio_last = %d\n",ud_ratio_last);
//	printf("lr_ratio_last = %d\n",lr_ratio_last);
//	printf("===============================================\n");
#endif	
    /* Determine the difference between the first and last ratios */
    ud_delta = ud_ratio_last - ud_ratio_first;
    lr_delta = lr_ratio_last - lr_ratio_first;
#if DEBUG
//	printf("===============================================\n");
//	printf("Delta:\n");
//	printf("ud_delta = %d\n",ud_delta);
//	printf("lr_delta = %d\n",lr_delta);
//	printf("===============================================\n");
#endif

    /* Accumulate the UD and LR delta values */
    gesture_ud_delta_ += ud_delta;
    gesture_lr_delta_ += lr_delta;
    
#if DEBUG
//	printf("===============================================\n");
//	printf("Accumulate Delta:\n");
//	printf("gesture_ud_delta_ = %d\n",gesture_ud_delta_);
//	printf("gesture_lr_delta_ = %d\n",gesture_lr_delta_);
//	printf("===============================================\n");
#endif
    /* Determine U/D gesture */
    if( gesture_ud_delta_ >= GESTURE_SENSITIVITY_1 ) //50
	{
        gesture_ud_count_ = 1;//U-->D
		//printf("U--->D\n");
    } 
	else if( gesture_ud_delta_ <= -GESTURE_SENSITIVITY_1 ) 
	{
        gesture_ud_count_ = -1;
		//printf("D--->U\n");
    } 
	else 
	{
        gesture_ud_count_ = 0;
    }
    
    /* Determine L/R gesture */
    if( gesture_lr_delta_ >= GESTURE_SENSITIVITY_1 ) 
	{
        gesture_lr_count_ = 1;
		//printf("L--->R\n");
    } 
	else if( gesture_lr_delta_ <= -GESTURE_SENSITIVITY_1 ) 
	{
        gesture_lr_count_ = -1;
		//printf("R--->L\n");
    }
	else 
	{
        gesture_lr_count_ = 0;
    }
    //printf("gesture_ud_count_ = %d\n",gesture_ud_count_);
	//printf("gesture_lr_count_ = %d\n",gesture_lr_count_);
    /* Determine Near/Far gesture */
    if( (gesture_ud_count_ == 0) && (gesture_lr_count_ == 0) ) 
	{
        if( (abs(ud_delta) < GESTURE_SENSITIVITY_2) && (abs(lr_delta) < GESTURE_SENSITIVITY_2) ) //20
		{    
            if( (ud_delta == 0) && (lr_delta == 0) ) 
			{
                gesture_near_count_++;
            }
			else if( (ud_delta != 0) || (lr_delta != 0) ) 
			{
                gesture_far_count_++;
            }
            
            if( (gesture_near_count_ >= 10) && (gesture_far_count_ >= 2) ) 
			{
                if( (ud_delta == 0) && (lr_delta == 0) ) 
				{
                    gesture_state_ = NEAR_STATE;
                }
				else if( (ud_delta != 0) && (lr_delta != 0) ) 
				{
                    gesture_state_ = FAR_STATE;
                }
                return true;
            }
        }
    } 
	else 
	{
        if( (abs((int)ud_delta) < GESTURE_SENSITIVITY_2) && (abs((int)lr_delta) < GESTURE_SENSITIVITY_2) ) 
		{
                
            if( (ud_delta == 0) && (lr_delta == 0) ) 
			{
                gesture_near_count_++;
            }
            
            if( gesture_near_count_ >= 10 ) 
			{
                gesture_ud_count_ = 0;
                gesture_lr_count_ = 0;
                gesture_ud_delta_ = 0;
                gesture_lr_delta_ = 0;
            }
        }
    }
#if DEBUG
//	printf("===============================================\n");
//	printf("UD_CT = %d\n",gesture_ud_count_);
//	printf("LR_CT = %d\n",gesture_lr_count_);
//	printf("NEAR_CT = %d\n",gesture_near_count_);
//	printf("FAR_CT = %d\n",gesture_far_count_);
//	printf("===============================================\n");
#endif
    return false;
}

/**
 * 确定滑动方向、远近状态
 *
 * @return True if near/far event. False otherwise.
 */
bool decodeGesture(void)
{
    /* Return if near or far event is detected */
    if( gesture_state_ == NEAR_STATE ) //手势状态 = 近距离
	{
        gesture_motion_ = DIR_NEAR;
        return true;
    } 
	else if ( gesture_state_ == FAR_STATE ) //手势状态 = 远距离
	{
        gesture_motion_ = DIR_FAR;
        return true;
    }
    
    /* Determine swipe direction 确定滑动方向 */
    if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == 0) )
	{
        gesture_motion_ = DIR_UP;
    } 
	else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == 0) ) 
	{
        gesture_motion_ = DIR_DOWN;
    } 
	else if( (gesture_ud_count_ == 0) && (gesture_lr_count_ == 1) ) 
	{
        gesture_motion_ = DIR_RIGHT;
    } 
	else if( (gesture_ud_count_ == 0) && (gesture_lr_count_ == -1) ) 
	{
        gesture_motion_ = DIR_LEFT;
    }
	else if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == 1) ) 
	{
        if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) 
		{
            gesture_motion_ = DIR_UP;
        } 
		else 
		{
            gesture_motion_ = DIR_RIGHT;
        }
    } 
	else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == -1) ) 
	{
        if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) 
		{
            gesture_motion_ = DIR_DOWN;
        } 
		else 
		{
            gesture_motion_ = DIR_LEFT;
        }
    } 
	else if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == -1) ) 
	{
        if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) 
		{
            gesture_motion_ = DIR_UP;
        } 
		else 
		{
            gesture_motion_ = DIR_LEFT;
        }
    } 
	else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == 1) ) 
	{
        if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) 
		{
            gesture_motion_ = DIR_DOWN;
        }
		else 
		{
            gesture_motion_ = DIR_RIGHT;
        }
    } 
	else 
	{
        return false;
    }
    return true;
}



/**
 * @brief Sets the LED current boost value
 *	设置LED当前的升压值
 * Value  Boost Current
 *   0        100%
 *   1        150%
 *   2        200%
 *   3        300%
 *
 * @param[in] drive the value (0-3) for current boost (100-300%)
 * @return True if operation successful. False otherwise.
 */
bool setLEDBoost(uint8_t boost)
{
    uint8_t val;
    
    /* Read value from CONFIG2 register */
    if( !wireReadDataByte(APDS9960_CONFIG2, &val) ) {
        return false;
    }
    
    /* Set bits in register to given value */
    boost &= 00000011;
    boost = boost << 4;
    val &= 11001111;
    val |= boost;
    
    /* Write register value back into CONFIG2 register */
    if( !wireWriteDataByte(APDS9960_CONFIG2, val) ) {
        return false;
    }
    
    return true;
}    
   

/***********************************************************************************
	设置手势接近进入阀值 
	APDS9960_GPENTH = threshold = 40
	0xA0 =  40
	0xA0的bit4必须设为0
	手势接近阀值会与接近数据PDATA进行比较并决定是否进入手势状态机
 ***********************************************************************************/
bool setGestureEnterThresh(uint8_t threshold)
{
    if( !wireWriteDataByte(APDS9960_GPENTH, threshold) )		
	{
        return false;
    }
    
    return true;
}


/***********************************************************************************
	设置手势接近退出阀值
	APDS9960_GEXTH = threshold  = 30
	0xA1 = 30
	此寄存器设置阀值决定手势结束,同时退出手势状态机.
	设置GTHR_OUT为0x00会防止手势退出直到GMODE被设为0
 ***********************************************************************************/
bool setGestureExitThresh(uint8_t threshold)
{
    if( !wireWriteDataByte(APDS9960_GEXTH, threshold) ) {
        return false;
    }
    
    return true;
}


/**
 * @brief Sets the gain of the photodiode during gesture mode
	gain = 2
 保留		7		写0
GGAIN		6:5		手势增益控制，设定一个增益手势接收在手势模式下
			0		1x
			1		2x
			2		4x
			3		8x
GLDRIVE		4:3		手势LED驱动强度
			0		100ma
			1		50ma
			2		25ma
			3		12.5ma
GWTIME		2:0		手势等待时间	
			0		0ms
			1		2.8ms
			2		5.6ms	
			3		8.4ms
			4		14.0ms
			5		22.4ms
			6		30.8ms
			7		39.2ms
 */
bool setGestureGain(uint8_t gain)
{
    uint8_t val;
    
    /* Read value from GCONF2 register */
    if( !wireReadDataByte(APDS9960_GCONF2, &val) ) 
	{
        return false;
    }
   // printf("First_Gain__0xA3 = %.2x\n",val);
    /* Set bits in register to given value */
    gain &= 00000011;//取gain最低两位
    gain = gain << 5;//移动到6:5  
    val &= 10011111;//将6:5位清零
    val |= gain;//将gain的6:5位赋值给val
   // printf("Last_Gain__0xA3 = %.2x\n",val);
    /* 然后在将val写入配置寄存器2设置增益(即用gain给其设置增益)*/
    if( !wireWriteDataByte(APDS9960_GCONF2, val) ) 
	{
        return false;
    }
    
    return true;
}


/**
 * @brief Sets the LED drive current during gesture mode
 *
 * Value    LED Current
 *   0        100 mA
 *   1         50 mA
 *   2         25 mA
 *   3         12.5 mA
 *
 * @param[in] drive the value for the LED drive current
 * @return True if operation successful. False otherwise.
 */
bool setGestureLEDDrive(uint8_t drive)
{
    uint8_t val;
    
    /* Read value from GCONF2 register */
    if( !wireReadDataByte(APDS9960_GCONF2, &val) ) 
	{
        return false;
    }
    //printf("First_LEDDrive__0xA3 = %.2x\n",val);
    /* Set bits in register to given value */
    drive &= 00000011;
    drive = drive << 3;//bit 4:3
    val &= 11100111;
    val |= drive;
    // printf("Last_LEDDrive__0xA3 = %.2x\n",val);
    /* Write register value back into GCONF2 register */
    if( !wireWriteDataByte(APDS9960_GCONF2, val) ) 
	{
        return false;
    }
    
    return true;
}


/**
 * @brief Sets the time in low power mode between gesture detections
 *
 * Value    Wait time
 *   0          0 ms
 *   1          2.8 ms
 *   2          5.6 ms
 *   3          8.4 ms
 *   4         14.0 ms
 *   5         22.4 ms
 *   6         30.8 ms
 *   7         39.2 ms
 *
 * @param[in] the value for the wait time
 * @return True if operation successful. False otherwise.
 */
bool setGestureWaitTime(uint8_t time)
{
    uint8_t val;
    
    /* Read value from GCONF2 register */
    if( !wireReadDataByte(APDS9960_GCONF2, &val))
	{
        return false;
    }
	//printf("First_WaitTime__0xA3 = %.2x\n",val);	
		
    /* Set bits in register to given value */
    time &= 00000111;
    val &= 11111000;
    val |= time;
    
    /* Write register value back into GCONF2 register */
    if( !wireWriteDataByte(APDS9960_GCONF2, val) ) 
	{
        return false;
    }
    //printf("Last_WaitTime__0xA3 = %.2x\n",val);
    return true;
}



/**
 * @brief Turns gesture-related interrupts on or off
 *
 * @param[in] enable 1 to enable interrupts, 0 to turn them off
 * @return True if operation successful. False otherwise.
 */
bool setGestureIntEnable(uint8_t enable)
{
    uint8_t val;
    
    /* Read value from GCONF4 register */
    if( !wireReadDataByte(APDS9960_GCONF4, &val) )
	{
        return false;
    }
   // printf("First_GIEN__0xAB = %.2x\n",val);
    /* Set bits in register to given value */
    enable &= 00000001;
    enable = enable << 1;
    val &= 11111101;
    val |= enable;
    //printf("Last_GIEN__0xAB = %.2x\n",val);
    /* Write register value back into GCONF4 register */
    if( !wireWriteDataByte(APDS9960_GCONF4, val) ) 
	{
        return false;
    }
    
    return true;
}



/**
 * @brief Tells the state machine to either enter or exit gesture state machine
 *
 * @param[in] mode 1 to enter gesture state machine, 0 to exit.
 * @return True if operation successful. False otherwise.
 */
bool setGestureMode(uint8_t mode)
{
    uint8_t val;
    
    /* Read value from GCONF4 register */
    if( !wireReadDataByte(APDS9960_GCONF4, &val) )	
	{
        return false;
    }
    
    /* Set bits in register to given value */
    mode &= 00000001;
    val &= 11111110;
    val |= mode;
    
    /* Write register value back into GCONF4 register */
    if( !wireWriteDataByte(APDS9960_GCONF4, val) ) {
        return false;
    }
    
    return true;
}


/**
 * @brief Writes a single byte to the I2C device and specified register
 *
 * @param[in] reg the register in the I2C device to write to
 * @param[in] val the 1-byte value to write to the I2C device
 * @return True if successful write operation. False otherwise.
 */
bool wireWriteDataByte(uint8_t reg, uint8_t val)
{
  IIC_Start(); 
	IIC_Send_Byte((APDS9960_I2C_ADDR<<1)|0);//发送器件地址+写命令	
	if(IIC_Wait_Ack())	//等待应答
	{
		IIC_Stop();		 
		return false;		
	}
  IIC_Send_Byte(reg);	//写寄存器地址
  IIC_Wait_Ack();		//等待应答 
	IIC_Send_Byte(val);//发送数据
	if(IIC_Wait_Ack())	//等待ACK
	{
		IIC_Stop();	 
		return false;		 
	}		 
    IIC_Stop();	 
	return true;

}



/**
 * @brief Reads a single byte from the I2C device and specified register
 *
 * @param[in] reg the register to read from
 * @param[out] the value returned from the register
 * @return True if successful read operation. False otherwise.
 */

bool wireReadDataByte(uint8_t reg,uint8_t *val)
{

	IIC_Start(); 
	IIC_Send_Byte((APDS9960_I2C_ADDR<<1)|0X00);//发送器件地址+写命令	
	IIC_Wait_Ack();		//等待应答 
	IIC_Send_Byte(reg);	//写寄存器地址
	IIC_Wait_Ack();		//等待应答
	IIC_Start();
	IIC_Send_Byte((APDS9960_I2C_ADDR<<1)|0x01);//发送器件地址+读命令	
	IIC_Wait_Ack();		//等待应答 
	*val=IIC_Read_Byte(0);//读取数据,发送nACK 
	IIC_Stop();			//产生一个停止条件 
	return true;	

//     IIC_Start(); 
//	IIC_Send_Byte((APDS9960_I2C_ADDR<<1)|0);//发送器件地址+写命令	
//	if(IIC_Wait_Ack())	//等待ACK
//	{
//		IIC_Stop();	 
//		return false;		 
//	}		//等待应答 
//    IIC_Send_Byte(reg);	//写寄存器地址
//    if(IIC_Wait_Ack())	//等待ACK
//	{
//		IIC_Stop();	 
//		return false;		 
//	}		//等待应答
//    IIC_Start();
//	IIC_Send_Byte((APDS9960_I2C_ADDR<<1)|1);//发送器件地址+读命令	
//    if(IIC_Wait_Ack())	//等待ACK
//	{
//		IIC_Stop();	 
//		return false;		 
//	}		//等待应答 
//	val=IIC_Read_Byte(0);//读取数据,发送nACK 
//    IIC_Stop();			//产生一个停止条件 
//	return true;	

}

/**
 * @brief Reads a block (array) of bytes from the I2C device and register
 *
 * @param[in] reg the register to read from
 * @param[out] val pointer to the beginning of the data
 * @param[in] len number of bytes to read
 * @return Number of bytes read. -1 on read error.
 */
int wireReadDataBlock( uint8_t reg,uint8_t *val, unsigned int len)
{
	unsigned char i = 0;
    IIC_Start(); 
    IIC_Send_Byte((APDS9960_I2C_ADDR<<1)|0);//发送器件地址+写命令	
	if(IIC_Wait_Ack())	//等待应答
	{
		IIC_Stop();		 
		return -1;		
	}
    IIC_Send_Byte(reg);	//写寄存器地址
    IIC_Wait_Ack();		//等待应答
    IIC_Start();
	IIC_Send_Byte((APDS9960_I2C_ADDR<<1)|1);//发送器件地址+读命令	
    IIC_Wait_Ack();		//等待应答 
	while(len)
	{		 

//		  if(i >= len)    //不能加，否则收不到数据
//		  {
//        return -1;
//      }
		if(len==1)
		{
			val[i]=IIC_Read_Byte(0);//读数据,发送nACK
		}
		else
		{
			val[i]=IIC_Read_Byte(1);		//读数据,发送ACK
		}
		i++; 
		len--;
	  }  
	  IIC_Stop();	//产生一个停止条件 
	  return i;
}



void Wire_begin_(void)
{
	  IIC_Init();

}

